package rs.etf.kdp.workstation;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

import javax.swing.JTextArea;

import rs.ac.bg.etf.sleep.simulation.Netlist;
import rs.ac.bg.etf.sleep.simulation.SimBuffer;
import rs.ac.bg.etf.sleep.simulation.Simulator;
import rs.ac.bg.etf.sleep.simulation.SimulatorMultithread;
import rs.ac.bg.etf.sleep.simulation.SimulatorOptimistic;
import rs.etf.kdp.server.InterthreadBuffer;
import rs.etf.kdp.server.Part;
import rs.etf.kdp.server.TokenizedConnection;

/**
 * @author Djordje Vukovic
 * @version 1.0
 * @created 25-May-2011 9:45:05 PM
 */
public class SimulationThread extends Thread{

	private Part myPart;
	private JTextArea out;
	private ObjectOutputStream output;
	private SimBuffer<Object> simBuffer;
	private Simulator<Object> simulator;
	InterthreadBuffer listenerThread;
	private boolean abort;
	
	@SuppressWarnings("unchecked")
	public SimulationThread(Part myPart, JTextArea out, ObjectOutputStream output, InterthreadBuffer buff){
		listenerThread = buff;
		this.myPart = myPart;
		this.out = out;
		abort = false;
		this.output = output;
		//simBuffer = new SimBufferImplementation<String>(myPart, 100, output);
		//simBuffer = new PrioritySimBuffer<Object>(myPart, 20, output);
		String className = (String)myPart.getType();
		
		@SuppressWarnings("rawtypes")
		Class sim = null;
		
		if(className.equals("SimulatorMultithread"))
		{
			try {
				sim = Class.forName("rs.ac.bg.etf.sleep.simulation.SimulatorMultithread");
			} catch (ClassNotFoundException e) {
				out.append("\nClass of simulator is not found");
			}
			
			@SuppressWarnings("rawtypes")
			Constructor constr = null;
			try {
				constr = sim.getConstructor(Integer.TYPE);
			} catch (SecurityException e1) {
				out.append("\nSecurity exception");
			} catch (NoSuchMethodException e1) {
				out.append("\nNo such method");
			}
			Object s = null;
			try {
				s = constr.newInstance(new Object[]{new Integer(1)});
			} catch (IllegalArgumentException e) {
				out.append("\nIllega class arguments");
			} catch (InstantiationException e) {
				out.append("\nInstantiation error");
			} catch (IllegalAccessException e) {
				out.append("\nIllegal access exception");
			} catch (InvocationTargetException e) {
				out.append("\nInvocetion target exception");
			}
			simulator = (SimulatorMultithread<Object>)s;
		} else
		{
			try {
				sim = Class.forName("rs.ac.bg.etf.sleep.simulation.SimulatorOptimistic");
			} catch (ClassNotFoundException e) {
				out.append("\nClass of simulator is not found");
			}
			
			@SuppressWarnings("rawtypes")
			Constructor constr = null;
			try {
				constr = sim.getConstructor(Integer.TYPE);
			} catch (SecurityException e1) {
				out.append("\nSecurity exception");
			} catch (NoSuchMethodException e1) {
				out.append("\nNo such method");
			}
			Object s = null;
			try {
				s = constr.newInstance(new Object[]{new Integer(1)});
			} catch (IllegalArgumentException e) {
				out.append("\nIllega class arguments");
			} catch (InstantiationException e) {
				out.append("\nInstantiation error");
			} catch (IllegalAccessException e) {
				out.append("\nIllegal access exception");
			} catch (InvocationTargetException e) {
				out.append("\nInvocetion target exception");
			}
			simulator = (SimulatorOptimistic<Object>)s;
		}
		
		
		
		simBuffer = new PrioritySimBuffer<Object>(myPart, output);
		simulator = new SimulatorMultithread<Object>(1);
		//simulator = new SimulatorOptimistic<Object>(1); 
	}
	
	@Override
	public void run() {
		out.append(myPart.getServerId() + "   " + myPart.getType());
		out.append("\n");
		Netlist<Object> netlist = partToNetlistObject(myPart);
		//simulator = new SimulatorOptimistic<Object>(1); 
		
		//SimBuffer<Object> simBuffer = new SimBufferImplementation<Object>(myPart, 121, output);
		//SimBuffer<Object> simBuffer = new PrioritySimBuffer<Object>(myPart, output);
		simulator.setNetlist(netlist);
		simulator.setQueue(simBuffer);
		simulator.init();
		long time = myPart.getLogicalTime();
		long prevLogTime = 0;
		out.append("\n" + "Time for job " + myPart.getServerId() + " is 0");
		try {
		while((simulator.getlTime() < time) && (!simulator.isEnd()))
		{
			simulator.execute();
			//out.append("\nTime: " + simulator.getlTime());
			if(prevLogTime < simulator.getlTime())
			{
				prevLogTime = simulator.getlTime();
				out.append("\n" + "Time for job " + myPart.getServerId() + " is " + simulator.getlTime());
			}
		}
		} 
		catch(Exception e)
		{
			e.printStackTrace();
		}
		out.append("\nFinished with simulating on job " + myPart.getServerId());
		
		if(abort)
		{
			out.append("\nSimulation is aborted");
			return;
		}
		String[][] state = simulator.getNetlist().getState();
		try {
			output.writeObject("result " + myPart.getServerId());
			output.writeObject(state);
		} catch (IOException e) {
			out.append("\nUnable to send result to server");
		}
		
	
	}

	public Part getMyPart() {
		return myPart;
	}

	public void setMyPart(Part myPart) {
		this.myPart = myPart;
	}

	public boolean isEnd() {
		return simulator.isEnd();
	}

	public void setEnd(boolean end) {
		simulator.setEnd(true);
	}

	public JTextArea getOut() {
		return out;
	}

	public void setOut(JTextArea out) {
		this.out = out;
	}

	public ObjectOutputStream getOutput() {
		return output;
	}

	public void setOutput(ObjectOutputStream output) {
		this.output = output;
	}

	public SimBuffer<Object> getSimBuffer() {
		return simBuffer;
	}

	public void setSimBuffer(SimBuffer<Object> simBuffer) {
		this.simBuffer = simBuffer;
	}
	
	private Netlist<Object> partToNetlistObject(Part myPart)
	{
		Netlist<Object> result = new Netlist<Object>();
		List<String> comps = myPart.getComponents();
		for(String s : comps)
		{
			//int firstSpace = s.indexOf(' ');
			//String id = s.substring(0,firstSpace);
			//int secondSpace = s.indexOf(' ', firstSpace+1);
			//String rest = s.substring(firstSpace+1, s.length());
			String componentArray[] = s.split(" ");
			//componentArray[0] = id;
			//componentArray[1] = rest;
			result.addComponent(componentArray);
		}
		
		List<TokenizedConnection> conns = myPart.getConnections();
		for(TokenizedConnection tc : conns)
		{
			long srcID = tc.getSrcID();
			int srcP = (int)tc.getSrcPort();
			long dstID = tc.getDstID();
			int dstP = (int)tc.getDstPort();
			result.addConnection(srcID, srcP, dstID, dstP);
		}
		
		return result;
	}

	public InterthreadBuffer getListenerThread() {
		return listenerThread;
	}

	public void setListenerThread(InterthreadBuffer listenerThread) {
		this.listenerThread = listenerThread;
	}

	public boolean isAbort() {
		return abort;
	}

	public void setAbort(boolean abort) {
		this.abort = abort;
	}
	
	

}